package edu.unlv.cs.ladders.util;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import edu.unlv.cs.ladders.entities.*;

@Component
public class JdbcAclStartupUtil {
	private static final String DROP_ACL_CLASS = "DROP TABLE IF EXISTS ACL_CLASS";
	private static final String DROP_ACL_ENTRY = "DROP TABLE IF EXISTS ACL_ENTRY CASCADE";
	private static final String DROP_ACL_OBJECT_IDENTITY = "DROP TABLE IF EXISTS ACL_OBJECT_IDENTITY CASCADE";
	private static final String DROP_ACL_SID = "DROP TABLE IF EXISTS ACL_SID";
	private static final String CREATE_ACL_CLASS = "CREATE TABLE "
			+ "`ACL_CLASS` (`ID` bigint(20) NOT NULL auto_increment,"
			+ "`CLASS` varchar(100) NOT NULL,"
			+ "PRIMARY KEY  (`ID`),"
			+ "UNIQUE KEY `UNIQUE_UK_2` (`CLASS`)"
			+ ") ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;";
	private static final String CREATE_ACL_ENTRY = "CREATE TABLE  "
			+ "`ACL_ENTRY` (`ID` bigint(20) NOT NULL auto_increment,"
			+ "`ACL_OBJECT_IDENTITY` bigint(20) NOT NULL,"
			+ "`ACE_ORDER` int(11) NOT NULL,"
			+ "`SID` bigint(20) NOT NULL,"
			+ "`MASK` int(11) NOT NULL,"
			+ "`GRANTING` tinyint(1) NOT NULL,"
			+ "`AUDIT_SUCCESS` tinyint(1) NOT NULL,"
			+ "`AUDIT_FAILURE` tinyint(1) NOT NULL,"
			+ "PRIMARY KEY  (`ID`),"
			+ "UNIQUE KEY `UNIQUE_UK_4` (`ACL_OBJECT_IDENTITY`,`ACE_ORDER`),"
			+ "KEY `SID` (`SID`)"
			+ ") ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;";
	private static final String CREATE_ACL_OBJECT_IDENTITY = "CREATE TABLE "
			+ "`ACL_OBJECT_IDENTITY` (`ID` bigint(20) NOT NULL auto_increment,"
			+ "`OBJECT_ID_CLASS` bigint(20) NOT NULL,"
			+ "`OBJECT_ID_IDENTITY` bigint(20) NOT NULL,"
			+ "`PARENT_OBJECT` bigint(20) default NULL,"
			+ "`OWNER_SID` bigint(20) default NULL,"
			+ "`ENTRIES_INHERITING` tinyint(1) NOT NULL,"
			+ "PRIMARY KEY  (`ID`),"
			+ "UNIQUE KEY `UNIQUE_UK_3` (`OBJECT_ID_CLASS`,`OBJECT_ID_IDENTITY`),"
			+ "KEY `OWNER_SID` (`OWNER_SID`),"
			+ "KEY `PARENT_OBJECT` (`PARENT_OBJECT`)"
			+ ") ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;";
	private static final String CREATE_ACL_SID = "CREATE TABLE "
			+ "`ACL_SID` (`ID` bigint(20) NOT NULL auto_increment,"
			+ "`PRINCIPAL` tinyint(1) NOT NULL,"
			+ "`SID` varchar(100) NOT NULL," + "PRIMARY KEY  (`ID`),"
			+ "UNIQUE KEY `UNIQUE_UK_1` (`PRINCIPAL`,`SID`)"
			+ ") ENGINE=InnoDB DEFAULT CHARSET=latin1;";
	private static final String ALTER_ACL_ENTRY = "ALTER TABLE `ACL_ENTRY`"
			+ "  ADD CONSTRAINT `ACL_ENTRY_ibfk_1` FOREIGN KEY (`SID`) REFERENCES `ACL_SID` (`ID`),"
			+ "  ADD CONSTRAINT `ACL_ENTRY_ibfk_2` FOREIGN KEY (`ACL_OBJECT_IDENTITY`) REFERENCES `ACL_OBJECT_IDENTITY` (`ID`);";
	private static final String ALTER_ACL_OBJECT_IDENTITY = "ALTER TABLE `ACL_OBJECT_IDENTITY`"
			+ "  ADD CONSTRAINT `ACL_OBJECT_IDENTITY_ibfk_1` FOREIGN KEY (`OWNER_SID`) REFERENCES `ACL_SID` (`ID`),"
			+ "  ADD CONSTRAINT `ACL_OBJECT_IDENTITY_ibfk_2` FOREIGN KEY (`OBJECT_ID_CLASS`) REFERENCES `ACL_CLASS` (`ID`),"
			+ "  ADD CONSTRAINT `ACL_OBJECT_IDENTITY_ibfk_3` FOREIGN KEY (`PARENT_OBJECT`) REFERENCES `ACL_OBJECT_IDENTITY` (`ID`);";
	private static final String INSERT_INTO_ACL_CLASS = "INSERT INTO ACL_CLASS (CLASS) VALUES (?),(?),(?),(?),(?),(?),(?)";
	private static final String INSERT_INTO_ACL_SID = "INSERT INTO ACL_SID (SID,PRINCIPAL) VALUES (?,?),(?,?),(?,?),(?,?)";

	
	private JdbcTemplate jdbcTemplate;
	private boolean dropCreate = true;
	@Autowired
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	@PostConstruct
	public void init() {
		if(isDropCreate()){
			dropAclEntry();
			dropAclObjectIdentity();
			dropAclClass();
			dropAclSid();
		}
		createAclClass();
		createAclEntry();
		createAclObjectIdentity();
		createAclSid();
		if(isDropCreate()){
			addForeignKeysToAclEntry();
			addForeignKeysToAclObjectIdentity();
			populateAclClass();
			populateAclSid();
		}
	}
	private void populateAclClass(){
		int rowsAffected = jdbcTemplate.update(INSERT_INTO_ACL_CLASS, 
				Challenge.class.getName(),
				Event.class.getName(),
				Participant.class.getName(),
				Score.class.getName(),
				Tag.class.getName(),
				Team.class.getName(),
				Tournament.class.getName());
		assert rowsAffected==7 : "Acl classes not inserted.";
	}
	private void populateAclSid(){
		int rowsAffected = jdbcTemplate.update(INSERT_INTO_ACL_SID,
				UserRole.ROLE_ADMIN,false,
				UserRole.ROLE_ANONYMOUS,false,
				UserRole.ROLE_COORDINATOR,false,
				UserRole.ROLE_PARTICIPANT,false);
		assert rowsAffected==5 : "Roles not inserted";
	}
	private void dropAclClass(){
		jdbcTemplate.execute(DROP_ACL_CLASS);
	}
	private void dropAclEntry(){
		jdbcTemplate.execute(DROP_ACL_ENTRY);
	}
	private void dropAclObjectIdentity(){
		jdbcTemplate.execute(DROP_ACL_OBJECT_IDENTITY);
	}
	private void dropAclSid(){
		jdbcTemplate.execute(DROP_ACL_SID);
	}
	private void createAclClass(){
		jdbcTemplate.execute(CREATE_ACL_CLASS);
	}
	private void createAclEntry(){
		jdbcTemplate.execute(CREATE_ACL_ENTRY);
	}
	private void createAclObjectIdentity(){
		jdbcTemplate.execute(CREATE_ACL_OBJECT_IDENTITY);
	}
	private void createAclSid(){
		jdbcTemplate.execute(CREATE_ACL_SID);
	}
	private void addForeignKeysToAclEntry(){
		jdbcTemplate.execute(ALTER_ACL_ENTRY);
		
	}
	private void addForeignKeysToAclObjectIdentity(){
		jdbcTemplate.execute(ALTER_ACL_OBJECT_IDENTITY);
	}
	/**
	 * @return the dropCreate
	 */
	public boolean isDropCreate() {
		return dropCreate;
	}

	/**
	 * @param dropCreate the dropCreate to set
	 */
	public void setDropCreate(boolean dropCreate) {
		this.dropCreate = dropCreate;
	}


}
